package com.shuma.product.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alipay.sofa.runtime.api.annotation.SofaReference;
import com.alipay.sofa.runtime.api.annotation.SofaReferenceBinding;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shuma.approval.service.ApprovalService;
import com.shuma.product.mapper.GoodsBaseInfoMapper;
import com.shuma.product.mapper.UserMapper;
import com.shuma.product.pojo.GoodsBaseInfo;
import com.shuma.product.pojo.GoodsDetailInfo;
import com.shuma.product.service.GoodsBaseInfoService;
import com.shuma.product.service.GoodsDetailInfoService;
import com.shuma.product.vo.req.GoodsBaseAndDetail;
import com.shuma.product.utils.CacheClient;
import com.shuma.common.vo.R;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.shuma.product.ExceptionEnum.ExceptionEnum.*;
import static com.shuma.product.utils.RedisConstants.*;

/**
 * @author 23083
 * @description 针对表【goods_base_info】的数据库操作Service实现
 * @createDate 2024-06-16 21:13:27
 */
@Service
public class GoodsBaseInfoServiceImpl extends ServiceImpl<GoodsBaseInfoMapper, GoodsBaseInfo>
        implements GoodsBaseInfoService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private CacheClient cacheClient;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private GoodsDetailInfoService goodsDetailInfoService;
    @SofaReference(interfaceType = ApprovalService.class, uniqueId = "${service.unique.id}", binding = @SofaReferenceBinding(bindingType = "bolt"))
    private ApprovalService approvalService;

    //分页查询 参数：当前用户id，第几页数据，每页大小，商品上下线状态，上线时间，下线时间，管理人的名字，当前用户的角色
    @Override
    public R getgoodsByoperatorid(Long id,Integer pagenum,Integer pagesize,
                                  Long goodsonlinestatus,
                                  Long goodsbaseid,
                                  String goodsname,
                                  LocalDateTime onlinetime,
                                  LocalDateTime expiretime,
                                  String operatorname,
                                  String role) {
        //设置要查询的第几页，每一页多少数据
        PageHelper.startPage(pagenum,pagesize);
        Page<GoodsBaseInfo> res = null;
        //管理员返回所有数据
        if(role.equals("admin")) {
            //查询分为不带时间端的和带时间端的
            if (onlinetime == null || expiretime == null)
                res = getBaseMapper().getAllgoodsbasenohavetime(goodsonlinestatus, goodsbaseid, goodsname, operatorname);
            else
                res = getBaseMapper().getAllgoodsbasehavetime(goodsonlinestatus, goodsbaseid, goodsname, onlinetime, expiretime, operatorname);
        }
        //普通用户查询出有自己有权限操作的商品
        else {
            //查询分为不带时间端的和带时间端的
            if (onlinetime == null || expiretime == null)
                res = getBaseMapper().getByoperatoridnohavetime(id, goodsonlinestatus, goodsbaseid, goodsname, operatorname);
            else
                res = getBaseMapper().getByoperatoridhavetime(id, goodsonlinestatus, goodsbaseid, goodsname, onlinetime, expiretime, operatorname);
        }
        //得到分页后的数据
        List<GoodsBaseInfo> goodsBaseInfoList = res.getResult();
        return R.ok(goodsBaseInfoList);
    }
    //得到基本商品信息 参数商品的id
    @Override
    public R getgoodsBybaseGoodsid(Long id) throws InterruptedException {
        //先从redis查，如没有再去mysql查询
        //参数：缓存key，锁key，id，数据类型，查找数据的函数，缓存时间，随机增加缓存时间的最大和最小值，时间类型
        GoodsBaseInfo goodsBaseInfo = cacheClient.queryWithPassThrough(
                CHACHE_BASEGOODSONE_KEY,LOCK_BASEGOODSONE_KEY,
                id, GoodsBaseInfo.class, ids->getBaseMapper().getBygoodsbaseid(ids),
                CHACHE_BASEGOODS_TTL,CHACHE_BASEGOODS_TTL_MIN,CHACHE_BASEGOODS_TTL_MAX,
                TimeUnit.MINUTES);
        //商品不存在
        if(goodsBaseInfo == null){
            return R.fail(GOODS_NOT_EXIST.getCode(),GOODS_NOT_EXIST.getMessage());
        }
        //先从redis查，如没有再去mysql查询
        GoodsDetailInfo goodsDetailInfo = cacheClient.queryWithPassThrough(
                CHACHE_GOODSTAILSONE_KEY,LOCK_GOODSTAILSONE_KEY,
                id, GoodsDetailInfo.class, ids-> goodsDetailInfoService.getById(ids),
                CHACHE_GOODSTAIL_TTL,CHACHE_GOODSTAIL_TTL_MIN,CHACHE_GOODSTAIL_TTL_MAX,
                TimeUnit.MINUTES);
        //商品不存在
        if(goodsDetailInfo == null){
            return R.fail(GOODS_NOT_EXIST.getCode(),GOODS_NOT_EXIST.getMessage());
        }
        //返回
        GoodsBaseAndDetail goodsBaseAndDetail =new GoodsBaseAndDetail();
        goodsBaseAndDetail.setGoodsBaseInfo(goodsBaseInfo);
        goodsBaseAndDetail.setGoodsDetailInfo(goodsDetailInfo);
        return R.ok(goodsBaseAndDetail);
    }

    //添加基本商品和详细
    @Override
    @Transactional
    public R addBaseDetailGood(GoodsBaseInfo goodsBaseInfo, GoodsDetailInfo goodsDetailInfo) throws InterruptedException {
        //判断要添加的商品是否合法
        if(!exactAllGood(goodsBaseInfo, goodsDetailInfo)){
            //参数错误
            return R.fail(GODDSCONTENTS_ERROR.getCode(),GODDSCONTENTS_ERROR.getMessage());
        }
        //针对个人加锁，防止短时刻内加多个相同的数据 参数（锁的名字）
        RLock lock = redissonClient.getLock(LOCK_ADDBASEGOODSONE_KEY+ goodsBaseInfo.getOperatorId());
        try {
            //尝试获取锁，参数（重试时间，锁的时间大小，锁的时间单位）
            boolean isLock = lock.tryLock(0, LOCK_BASEGOODS_TTL, TimeUnit.SECONDS);
            if (!isLock) {
                //如果没有获取到，说明前一刻你正在进行添加，返回操作已经存在
                return R.fail(OPERATION_EXIST.getCode(), OPERATION_EXIST.getMessage());
            }
            //设置两个参数默认值
            if(goodsDetailInfo.getCashPrice() == null)
                goodsDetailInfo.setCashPrice(0);
            if(goodsDetailInfo.getIntegralPrice() == null)
                goodsDetailInfo.setIntegralPrice(0);
            boolean isadd1 = save(goodsBaseInfo);
            boolean isadd2 = goodsDetailInfoService.save(goodsDetailInfo);
            //数据库操作失败，返回错误信息
            if (!isadd1 || !isadd2) {
                return R.fail(ADDOPERATION_FAIL.getCode(), ADDOPERATION_FAIL.getMessage());
            }
        }finally {
            //锁中会存放由当前线程的唯一id组成的字符串。只有本线程才会释放锁
            lock.unlock();
        }
        return R.ok();
    }

    //逻辑删除基本商品，物理删除详细 当前商品的id
    @Override
    @Transactional
    public R deleteBaseDetailGood(Long id) throws InterruptedException {
        //查询数据是否存在
        GoodsBaseInfo ibaseGoodsBaseInfo = cacheClient.queryWithPassThrough(
                CHACHE_BASEGOODSONE_KEY,LOCK_BASEGOODSONE_KEY,
                id, GoodsBaseInfo.class, ids->getBaseMapper().getBygoodsbaseid(ids),
                CHACHE_BASEGOODS_TTL,CHACHE_BASEGOODS_TTL_MIN,CHACHE_BASEGOODS_TTL_MAX,
                TimeUnit.MINUTES);
        if(ibaseGoodsBaseInfo ==null){
            //商品不存在，不能进行删除操作
            return R.fail(GOODS_NOT_EXIST.getCode(),GOODS_NOT_EXIST.getMessage());
        }
        //对更新和删除的商品加同一把锁，防止高并发情况下的错误发生 参数（锁的名字）
        RLock lock = redissonClient.getLock(LOCK_UPDATABASEGOODSONE_KEY+id);
        try {
            //尝试获取锁，参数（重试时间，锁的时间大小，锁的时间单位）
            boolean isLock = lock.tryLock(0, LOCK_BASEGOODS_TTL, TimeUnit.SECONDS);
            if (!isLock) {
                return R.fail(OPERATION_EXIST.getCode(), OPERATION_EXIST.getMessage());
            }
            //更新数据库
            ibaseGoodsBaseInfo.setIsdelete(new Integer(1));
            boolean isdelete1 = updateById(ibaseGoodsBaseInfo);
            boolean isdelete2 = goodsDetailInfoService.removeById(id);
            //删除操作失败
            if (!isdelete1 || !isdelete2) {
                return R.fail(DELETEOPERATION_FAIL.getCode(), DELETEOPERATION_FAIL.getMessage());
            }
        }finally {
            //删除缓存
            stringRedisTemplate.delete(CHACHE_BASEGOODSONE_KEY + id);
            stringRedisTemplate.delete(CHACHE_GOODSTAILSONE_KEY + id);
            //锁中会存放由当前线程的唯一id组成的字符串。只有本线程才会释放锁
            lock.unlock();
        }
        return R.ok();
    }
    //更新基本商品 当前商品的id，上下线的数据0 下线 ，1上线
    @Override
    @Transactional
    public R updateonlineBaseGood(Long id,Integer onlinestatus) throws InterruptedException {
        //查询数据是否存在
        GoodsBaseInfo ibaseGoodsBaseInfo = cacheClient.queryWithPassThrough(
                CHACHE_BASEGOODSONE_KEY,LOCK_BASEGOODSONE_KEY,
                id, GoodsBaseInfo.class, ids->getBaseMapper().getBygoodsbaseid(ids),
                CHACHE_BASEGOODS_TTL,CHACHE_BASEGOODS_TTL_MIN,CHACHE_BASEGOODS_TTL_MAX,
                TimeUnit.MINUTES);
        if(ibaseGoodsBaseInfo ==null){
            //商品不存在
            return R.fail(GOODS_NOT_EXIST.getCode(),GOODS_NOT_EXIST.getMessage());
        }
        //商品审核未通过，不能进行上下线操作
        if(!ibaseGoodsBaseInfo.getGoodsCheckStatus().equals(2)){
            return R.fail(CHECHATNOPASS_FAIL.getCode(),CHECHATNOPASS_FAIL.getMessage());
        }
        //对更新和删除的商品加同一把锁，防止高并发情况下的错误发生 参数（锁的名字）
        RLock lock = redissonClient.getLock(LOCK_UPDATABASEGOODSONE_KEY+ id);
        try {
            //尝试获取锁，参数（重试时间，锁的时间大小，锁的时间单位）
            boolean isLock = lock.tryLock(0, LOCK_BASEGOODS_TTL, TimeUnit.SECONDS);
            //获取锁失败
            if (!isLock) {
                return R.fail(OPERATION_EXIST.getCode(), OPERATION_EXIST.getMessage());
            }
            //更新数据库
            ibaseGoodsBaseInfo.setGoodsOnlineStatus(onlinestatus);
            boolean isupdate = updateById(ibaseGoodsBaseInfo);
            //添加数据库失败
            if (!isupdate) {
                return R.fail(UPDATEONLINE_FAIL.getCode(), UPDATEONLINE_FAIL.getMessage());
            }
            // 操作日志表记录上下线操作
            approvalService.savaOperatorLog(id, "", onlinestatus, StpUtil.getLoginIdAsLong());
        }finally {
            String keyname=CHACHE_BASEGOODSONE_KEY + id;
            //删除缓存
            stringRedisTemplate.delete(keyname);
            //锁中会存放由当前线程的唯一id组成的字符串。只有本线程才会释放锁
            lock.unlock();
        }
        return R.ok();
    }
    //将基本和详细商品同时更新
    @Override
    public R updateBaseDetailGood(GoodsBaseInfo goodsBaseInfo, GoodsDetailInfo goodsDetailInfo) throws InterruptedException {
        //判断更新的数据是否基本合法
        if(!exactAllGood(goodsBaseInfo, goodsDetailInfo)){
            //参数错误
            return R.fail(GODDSCONTENTS_ERROR.getCode(),GODDSCONTENTS_ERROR.getMessage());
        }
        //查询数据是否存在
        GoodsBaseInfo ibaseGoodsBaseInfo = cacheClient.queryWithPassThrough(
                CHACHE_BASEGOODSONE_KEY,LOCK_BASEGOODSONE_KEY,
                goodsBaseInfo.getGoodsBaseId(), GoodsBaseInfo.class, ids->getBaseMapper().getBygoodsbaseid(ids),
                CHACHE_BASEGOODS_TTL,CHACHE_BASEGOODS_TTL_MIN,CHACHE_BASEGOODS_TTL_MAX,
                TimeUnit.MINUTES);
        if(ibaseGoodsBaseInfo ==null){
            //商品不存在
            return R.fail(GOODS_NOT_EXIST.getCode(),GOODS_NOT_EXIST.getMessage());
        }
        //针对商品 对更新和删除的商品加同一把锁，防止高并发情况下的错误发生 参数（锁的名字）
        RLock lock = redissonClient.getLock(LOCK_UPDATABASEGOODSONE_KEY+ goodsBaseInfo.getGoodsBaseId());
        try {
            //尝试获取锁，参数（重试时间，锁的时间大小，锁的时间单位）
            boolean isLock = lock.tryLock(0, LOCK_BASEGOODS_TTL, TimeUnit.SECONDS);
            if (!isLock) {
                return R.fail(OPERATION_EXIST.getCode(), OPERATION_EXIST.getMessage());
            }
            //更新数据库
            //设置两个参数默认值
            if(goodsDetailInfo.getCashPrice() == null)
                goodsDetailInfo.setCashPrice(0);
            if(goodsDetailInfo.getIntegralPrice() == null)
                goodsDetailInfo.setIntegralPrice(0);
            boolean isupdate1 = updateById(goodsBaseInfo);
            boolean isupdate2 = goodsDetailInfoService.updateById(goodsDetailInfo);
            //更新数据失败
            if (!isupdate1 || !isupdate2) {
                return R.fail(UPDATEOPERATION_FAIL.getCode(), UPDATEOPERATION_FAIL.getMessage());
            }
        }finally {
            //删除缓存
            stringRedisTemplate.delete(CHACHE_BASEGOODSONE_KEY +  goodsBaseInfo.getGoodsBaseId());
            stringRedisTemplate.delete(CHACHE_GOODSTAILSONE_KEY +  goodsDetailInfo.getGoodsDetailId());
            //锁中会存放由当前线程的唯一id组成的字符串。只有本线程才会释放锁
            lock.unlock();
        }
        return R.ok();
    }

    public boolean exactAllGood(GoodsBaseInfo goodsBaseInfo, GoodsDetailInfo goodsDetailInfo){
        //id不同，不能更新
        if(!goodsBaseInfo.getGoodsBaseId().equals(goodsDetailInfo.getGoodsDetailId()))
            return false;
        //判断是否基本合法
        if(!exactBaseGood(goodsBaseInfo)||!goodsDetailInfoService.exactGoodDail(goodsDetailInfo))
            return false;
        //如果不是草稿状态，不能有空字符串
        if(!goodsBaseInfo.getGoodsOwnerStatus().equals(1)){
            if(//goodsDetailInfo.getGoodsAvatar().trim().isEmpty()||
                    goodsDetailInfo.getDescription().trim().isEmpty()||
                    goodsDetailInfo.getGoodsRich().trim().isEmpty()||
                    goodsDetailInfo.getSuppier().trim().isEmpty()||
                    goodsDetailInfo.getSuppierConnect().trim().isEmpty()||
                    goodsDetailInfo.getServiceGuarante().trim().isEmpty()||
                    goodsDetailInfo.getCityWhitlist().trim().isEmpty()||
                    goodsDetailInfo.getCityBlacklist().trim().isEmpty()||
                    goodsBaseInfo.getGoodsName().trim().isEmpty()||
                    goodsBaseInfo.getOperator().trim().isEmpty()||
                    goodsDetailInfo.getCreateTime() == null ||
                    goodsDetailInfo.getUpdateTime() == null ||
                    goodsBaseInfo.getExpireTime() == null ||
                    goodsBaseInfo.getOnlineTime() == null ||
                    goodsBaseInfo.getOnlineTime().isAfter(goodsBaseInfo.getExpireTime()))
                    //goodsDetailInfo.getCreateTime().isAfter(goodsDetailInfo.getUpdateTime()))
                return false;
        }
        return true;
    }

    //判断商品base是否合法
    public boolean exactBaseGood(GoodsBaseInfo goodsBaseInfo){
        //数据的基本不能为空
        if(goodsBaseInfo.getGoodsBaseId() == null||
                goodsBaseInfo.getGoodsName() == null||
                goodsBaseInfo.getGoodsStock() ==null||
                goodsBaseInfo.getOperator() == null||
                goodsBaseInfo.getGoodsOwnerStatus() == null||
                goodsBaseInfo.getGoodsCheckStatus() == null||
                goodsBaseInfo.getGoodsOnlineStatus() == null||
                goodsBaseInfo.getOperatorId() == null||
                goodsBaseInfo.getIsdelete() == null||
                goodsBaseInfo.getGoodsOwnerStatus()<1||
                goodsBaseInfo.getGoodsOwnerStatus()>3||
                goodsBaseInfo.getGoodsCheckStatus()<1||
                goodsBaseInfo.getGoodsCheckStatus()>3||
                goodsBaseInfo.getGoodsOnlineStatus()<1||
                goodsBaseInfo.getGoodsOnlineStatus()>3||
                goodsBaseInfo.getGoodsName().length()>100||
                goodsBaseInfo.getOperator().length()>100)
            return false;
        //1.草稿的不合理状态 当前为草稿，getGoodsCheckStatus就不能 2.审核通过、3.审核驳回
        //                          getGoodsOnlineStatus就不能2.已上线、3.已下线
        if(goodsBaseInfo.getGoodsOwnerStatus().equals(1)){
            if(goodsBaseInfo.getGoodsCheckStatus().equals(2)||
                    goodsBaseInfo.getGoodsCheckStatus().equals(3)||
                    goodsBaseInfo.getGoodsOnlineStatus().equals(2)||
                    goodsBaseInfo.getGoodsOnlineStatus().equals(3))
                return false;
        }
        //2.已编辑的不合理状态
        //getGoodsCheckStatus就不能为 2.审核通过、3.审核驳回
        // getGoodsOnlineStatus不能为2.已上线、3.已下线
        if(goodsBaseInfo.getGoodsOwnerStatus().equals(2)){
            if(goodsBaseInfo.getGoodsCheckStatus().equals(2)||
                    goodsBaseInfo.getGoodsCheckStatus().equals(3)||
                    goodsBaseInfo.getGoodsOnlineStatus().equals(2)||
                    goodsBaseInfo.getGoodsOnlineStatus().equals(3))
                return false;
        }
        return true;
    }
}




